package com.example.autumn.context;

import com.example.autumn.annotation.*;
import com.example.autumn.exeception.*;
import com.example.autumn.io.AutumnFactoriesLoader;
import com.example.autumn.io.PropertyResolver;
import com.example.autumn.io.ResourceResolver;
import com.example.autumn.utils.ClassPathUtils;
import com.example.autumn.utils.ClassUtils;
import jakarta.annotation.Nullable;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author liuzhiyong
 * @date 2023/10/18
 * description: 应用上下文
 */
public class AnnotationConfigApplicationContext implements ConfigurableApplicationContext {


    protected final Logger logger = LoggerFactory.getLogger(getClass());
    protected final PropertyResolver propertyResolver;
    protected final Map<String, BeanDefinition> beans;

    /**
     * bean的后置处理器集合
     */
    List<BeanPostProcessor> beanPostProcessors = new ArrayList<>();

    /**
     * 存储正在创建的beanNam,追踪正在创建的Bean
     */
    Set<String> creatingBeanNames;

    /**
     * 构造方法
     *
     * @param configClass  配置类, 扫描此类所在的包以及子包的类, 如果`ComponentScan`注解指定了扫描的路径, 就扫描指定路径
     * @param propertyResolver 属性解析器, 解析配置文件
     * @author liuzhiyong
     * @date 2023/10/19
     */
    public AnnotationConfigApplicationContext(Class<?> configClass, PropertyResolver propertyResolver) {
        ApplicationContextUtils.setApplicationContext(this);

        //************************创建Bean定义信息****************************

        this.propertyResolver = propertyResolver;
        // 扫描所有Bean的Class类型
        final Set<String> beanClassNames = scanForClassNames(configClass);
        //创建Bean的定义信息
        this.beans = createBeanDefinitions(beanClassNames);

        //***************************创建Bean*******************************

        // 创建BeanName用于检测循环依赖
        this.creatingBeanNames = new HashSet<>();
        // @Configuration注解的标注的类, 实际上是工厂, 必须把工厂的Bean创建出来, 才能创建其他普通的Bean
        //创建@Configuration类型的Bean
        this.beans.values().stream()
                // 过滤出@Configuration
                .filter(this::isConfigurationDefinition)
                .sorted()
                .map(def -> {
                    createBeanAsEarlySingleton(def);
                    return def.getName();
                })
                .collect(Collectors.toList());


        // 创建BeanPostProcesser类型的Bean, 后续在创建Bean的时候, 可以使用BeanPostProcessor将原来的Bean替换为代理Bean
        // 因为使用BeanPostProcessor可能会使用代理类替换掉原有的Bean, 这时候原有的Bean还没有注入依赖,也没有执行init函数, 需要保存原有的Bean, 注入依赖的时候,注入到原有的Bean, 代理Bean注入到调用方
        // 所有需要修改下面初始化Bean的方法, 获取Bean的时候, 应该判断有没有被BeanPostProcessor修改过, 是不是原对象, 不是原对象的话, 需要获取到原来的对象
        List<BeanPostProcessor> processors = this.beans.values().stream()
                // 过滤出BeanPostProcessor
                .filter(this::isBeanPostProcessorDefinition)
                // 排序
                .sorted()
                // 实例化
                .map(def -> (BeanPostProcessor) createBeanAsEarlySingleton(def))
                .collect(Collectors.toList());
        this.beanPostProcessors.addAll(processors);


        // 创建其他普通的Bean
        createNormalBeans();

        if (logger.isDebugEnabled()) {
            this.beans.values().stream().sorted().forEach(def -> {
                logger.debug("bean initialized: {}", def);
            });
        }

        //***************************初始化Bean*******************************
        // @Value和@Autowired都是可以加在属性上和setter方法上的
        // 根据Setter方法和字段注入完成弱依赖注入(标注@Value 和 @Autowired注解属性或者setter函数) + 调用@PostConstruct标注的init方法

        // 通过字段和setter方法注入依赖
        // 需要判断当前Bean是否被BeanPostProcessor替代过对象
        this.beans.values().forEach(this::injectBean);

        // 调用init方法 也就是加了@PostConstruct注解的方法, 或者@Bean注解指定了初始化函数名的方法
        // 需要判断当前Bean是否被BeanPostProcessor替代过对象
        this.beans.values().forEach(this::initBean);

    }

    /**
     * 创建普通的Bean
     *
     * @author liuzhiyong
     * @date 2023/10/21
     */
    void createNormalBeans() {
        List<BeanDefinition> defs = this.beans.values().stream()
                // 过滤出instance==null的BeanDefinition, @Configuration标注的类已经在上面被创建了, instance不为null
                .filter(def -> def.getInstance() == null)
                .sorted()
                .toList();

        // 依次创建Bean实例
        defs.forEach(def -> {
            // 如果Bean未被创建(可能在其他Bean的构造方法注入前被创建)
            if (def.getInstance() == null) {
                // 创建Bean
                createBeanAsEarlySingleton(def);
            }
        });
    }


    /**
     * 扫描响应的包路径, 并且返回类名
     *
     * @param configClass 配置类, 指定扫描的包路径, 类似于SpringBoot项目的启动类
     * @return {@link Set<String> }
     * @author liuzhiyong
     * @date 2023/10/19
     */
    protected Set<String> scanForClassNames(Class<?> configClass) {
        // 获取要扫描的package名称
        // 获取configClass上的ComponentScan注解, 递归获取
        ComponentScan scan = ClassUtils.findAnnotation(configClass, ComponentScan.class);
        // 如果scan为null 或者 没有指定扫描路径, 扫描configClass所在的包, 否则扫描scan中value指定的包路径
        final String[] scanPackageArray = scan == null || scan.value().length == 0 ? new String[] {configClass.getPackage().getName()} :scan.value();
        Set<String> scanPackages = new HashSet<>(Arrays.asList(scanPackageArray));
        // 保存类名的Set集合
        Set<String> classNameSet = new HashSet<>();
        // 扫描META-INF下的import文件
        scanMetaInf(scanPackages, classNameSet);
        logger.atDebug().log("component scan in packages: {}", scanPackages);
        // 循环遍历指定扫描的包路径, 扫描其子包, 获取类名
        for (String pkg : scanPackages) {
            logger.atDebug().log("scan package: {}", pkg);
            // 创建指定包的资源解析解析器
            var rr = new ResourceResolver(pkg);
            // 扫描改包下的资源, 指定资源的映射函数==>获取class文件的名称
            // 例如: "org/example/Hello.class". 需要转成类名,例如: "org.example.Hello"
            List<String> classList = rr.scan(res -> {
                String name = res.name();
                if (name.endsWith(".class")) {
                    return name.substring(0, name.length() - 6).replace("/", ".").replace("\\", ".");
                }
                return null;
            });
            // debug级别, 打印类名
            if (logger.isDebugEnabled()) {
                classList.forEach((className) -> {
                    logger.debug("class found by component scan: {}", className);
                });
            }
            classNameSet.addAll(classList);
        }

        // 查找@Import(Xyz.class)
        // 注释掉的代码为原来的逻辑, 不支持多级的Import注解的查找
//        Import importConfig = configClass.getAnnotation(Import.class);
        List<Import> importConfigList = ClassUtils.findAnnotationList(configClass, Import.class, null);
        for (Import importConfig : importConfigList) {
            if (importConfig != null) {
                for (Class<?> importConfigClass : importConfig.value()) {
                    String importClassName = importConfigClass.getName();
                    if (classNameSet.contains(importClassName)) {
                        logger.warn("ignore import: " + importClassName + " for it is already been scanned.");
                    } else {
                        logger.debug("class found by import: {}", importClassName);
                        classNameSet.add(importClassName);
                    }
                }
            }
        }

        return classNameSet;
    }

    /**
     * 扫描META-INF/spring/import文件
     *
     * @author liuzhiyong
     * @date 2023/11/10
     */
    private void scanMetaInf(Set<String> scanPackages, Set<String> classNameSet) {
        List<String> names = new AutumnFactoriesLoader().loadImport();
        for (String name : names) {
            if (name != null && name.strip().length() > 0) {
                // 添加到类名集合中
                classNameSet.add(name);
                try {
                    Class<?> clazz = Class.forName(name);
                    ComponentScan componentScan = ClassUtils.findAnnotation(clazz, ComponentScan.class);
                    // 如果有ComponentScan注解, 添加扫描路径
                    if (componentScan != null) {
                        final String[] scanPackageArray = componentScan.value().length == 0 ? new String[] {clazz.getPackage().getName()} : componentScan.value();
                        scanPackages.addAll(Arrays.asList(scanPackageArray));
                    }
                } catch (ClassNotFoundException e) {
                    logger.warn("", e);
                }
            }
        }
    }

    /**
     * 判断Bean Definition中是否有@Configuration注解
     *
     * @param def Bean的定义信息
     * @return {@link boolean } true=有@Configuration注解/false=没有@Configuration注解
     * @author liuzhiyong
     * @date 2023/10/21
     */
    boolean isConfigurationDefinition(BeanDefinition def) {
        return ClassUtils.findAnnotation(def.getBeanClass(), Configuration.class) != null;
    }

    /**
     * 判断是否为BeanPostProcessor的BeanDefinition
     *
     * @param def bean的定义信息
     * @return {@link boolean } true=是BeanPostProcessor/false=不是BeanPostProcessor
     * @author liuzhiyong
     * @date 2023/10/24
     */
    boolean isBeanPostProcessorDefinition(BeanDefinition def) {
        // BeanPostProcessor的子类会返回true
        return BeanPostProcessor.class.isAssignableFrom(def.getBeanClass());
    }

    /**
     * 根据扫描的ClassName创建BeanDefinition
     *
     * @param beanClassNames bean的名称集合
     * @return {@link Map<String,BeanDefinition> } bean定义信息 map
     * @author liuzhiyong
     * @date 2023/10/19
     */
    Map<String, BeanDefinition> createBeanDefinitions(Set<String> beanClassNames) {
        Map<String, BeanDefinition> defs = new HashMap<>();
        for (String className : beanClassNames) {
            // 获取Class
            Class<?> clazz = null;
            try {
                clazz = Class.forName(className);
            } catch (ClassNotFoundException e) {
                throw new BeanCreationException(e);
            }
            // 注解, 枚举, 接口,Record类型 ==> 不创建bean的定义信息
            if (clazz.isAnnotation() || clazz.isEnum() || clazz.isInterface() || clazz.isRecord()) {
                continue;
            }
            // 是否标注@Component ==> 标注了@Component注解创建BeanDefinition
            // 递归获取@Component注解
            Component component = ClassUtils.findAnnotation(clazz, Component.class);
            if (component != null) {
                logger.atDebug().log("found component: {}", clazz.getName());
                // 获取该类的修饰符类型 ==> 公共类, 抽象类, 内部类等
                int mod = clazz.getModifiers();
                // 判断是否为抽象类 ==> 抽象类不能加@Component注解, 不需要创建Bean Definition
                if (Modifier.isAbstract(mod)) {
                    throw new BeanDefinitionException("@Component class " + clazz.getName() + " must not be abstract.");
                }
                // 判断类的权限是否为private ==> private的内部类不能加@Component注解, 不需要创建Bean Definition
                if (Modifier.isPrivate(mod)) {
                    throw new BeanDefinitionException("@Component class " + clazz.getName() + " must not be private.");
                }
                // 获取递归获取@Component注解中value指定的名称, 或者包含@Component注解的value指定的名称, 如果没有执行, 会将类名转成小驼峰, 作为beanName
                String beanName = ClassUtils.getBeanName(clazz);
                var def = new BeanDefinition(beanName, clazz, getSuitableConstructor(clazz), getOrder(clazz), clazz.isAnnotationPresent(Primary.class),
                        null, null,
                        // init method:
                        ClassUtils.findAnnotationMethod(clazz, PostConstruct.class),
                        // destroy method:
                        ClassUtils.findAnnotationMethod(clazz, PreDestroy.class));
                addBeanDefinitions(defs, def);
                logger.atDebug().log("define bean: {}", def);

                // 判断当前类是否包含 @Configuration注解, 如果包含的话, 扫描其中有@Bean注解的函数, 创建BeanDefinition
                Configuration configuration = ClassUtils.findAnnotation(clazz, Configuration.class);
                if (configuration != null) {
                    scanFactoryMethods(beanName, clazz, defs);
                }
            }

        }
        return defs;
    }

    /**
     * 获取构造函数
     *
     * @param clazz
     * @return {@link Constructor<?> }
     * @author liuzhiyong
     * @date 2023/10/20
     */
    Constructor<?> getSuitableConstructor(Class<?> clazz) {
        // 获取class所有公共的构造函数, 包括父类的
        Constructor<?>[] cons = clazz.getConstructors();
        if (cons.length == 0) {
            // 获取class所有的构造函数(包括公共,默认,受保护,私有的, 但不包括从父类获得的构造函数)
            cons = clazz.getDeclaredConstructors();
            if (cons.length != 1) {
                throw new BeanDefinitionException("More than one constructor found in class " + clazz.getName() + ".");
            }
        }
        if (cons.length != 1) {
            throw new BeanDefinitionException("More than one public constructor found in class " + clazz.getName() + ".");
        }
        return cons[0];
    }

    /**
     * 获取排序
     * <code>
     * &#64;Order(100)
     * &#64;Component
     * public class Hello{}
     * </code>
     *
     * @param clazz class对象
     * @return {@link int }
     * @author liuzhiyong
     * @date 2023/10/20
     */
    int getOrder(Class<?> clazz) {
        Order order = clazz.getAnnotation(Order.class);
        return order == null ? Integer.MAX_VALUE : order.value();
    }

    /**
     * Get order by:
     *
     * <code>
     * &#64;Order(100)
     * &#64;Bean
     * Hello createHello() {
     *     return new Hello();
     * }
     * </code>
     */
    int getOrder(Method method) {
        Order order = method.getAnnotation(Order.class);
        return order == null ? Integer.MAX_VALUE : order.value();
    }

    /**
     * 添加BeanDefinition到Map
     *
     * @param defs map
     * @param def  bean定义信息
     * @author liuzhiyong
     * @date 2023/10/20
     */
    void addBeanDefinitions(Map<String, BeanDefinition> defs, BeanDefinition def) {
        // put()函数, key重复的话, 会返回旧的value值, 其他情况返回null, 不为null的话说明key重复
        if (defs.put(def.getName(), def) != null) {
            throw new BeanDefinitionException("Duplicate bean name: " + def.getName());
        }
    }

    /**
     *
     *
     * @param factoryBeanName 工厂对象名称
     * @param clazz
     * @param defs
     * @author liuzhiyong
     * @date 2023/10/20
     */
    void scanFactoryMethods(String factoryBeanName, Class<?> clazz, Map<String, BeanDefinition> defs) {
        // 获取所有方法
        for (Method method : clazz.getDeclaredMethods()) {
            // 获取@Bean注解, 判断方法上是否有@Bean注解
            Bean bean = method.getAnnotation(Bean.class);
            if (bean != null) {
                // 获取方法权限
                int mod = method.getModifiers();
                // 抽象方法 ==> 不能使用@Bean
                if (Modifier.isAbstract(mod)) {
                    throw new BeanDefinitionException("@Bean method " + clazz.getName() + "." + method.getName() + " must not be abstract.");
                }
                // final修饰的方法 ==> 不能使用@Bean
                if (Modifier.isFinal(mod)) {
                    throw new BeanDefinitionException("@Bean method " + clazz.getName() + "." + method.getName() + " must not be final.");
                }
                // 私有方法 ==> 不能使用@Bean
                if (Modifier.isPrivate(mod)) {
                    throw new BeanDefinitionException("@Bean method " + clazz.getName() + "." + method.getName() + " must not be private.");
                }
                // 获取返回值类型
                Class<?> beanClass = method.getReturnType();
                // 判断返回值是否为基础数据类型 ==> 返回值不允许为基础数据类型
                if (beanClass.isPrimitive()) {
                    throw new BeanDefinitionException("@Bean method " + clazz.getName() + "." + method.getName() + " must not return primitive type.");
                }
                // 判断返回值是都为void 或者 Void, ==> 不允许没有返回值
                if (beanClass == void.class || beanClass == Void.class) {
                    throw new BeanDefinitionException("@Bean method " + clazz.getName() + "." + method.getName() + " must not return void.");
                }
                //
                var def = new BeanDefinition(ClassUtils.getBeanName(method), beanClass, factoryBeanName, method, getOrder(method),
                        method.isAnnotationPresent(Primary.class),
                        // init method:
                        bean.initMethod().isEmpty() ? null : bean.initMethod(),
                        // destroy method:
                        bean.destroyMethod().isEmpty() ? null : bean.destroyMethod(),
                        // @PostConstruct / @PreDestroy method:
                        null, null);
                addBeanDefinitions(defs, def);
                logger.atDebug().log("define bean: {}", def);
            }
        }
    }


    /**
     * 根绝那么查询Bean Definition 如果Name不存在返回Null
     *
     * @param name 名称
     * @return {@link BeanDefinition }
     * @author liuzhiyong
     * @date 2023/10/20
     */
    @Nullable
    @Override
    public BeanDefinition findBeanDefinition(String name) {
        return this.beans.get(name);
    }

    /**
     * 根据Name和Type查找BeanDefinition，如果Name不存在，返回null，如果Name存在，但Type不匹配，抛出异常。
     *
     * @param name bean名称
     * @param requiredType 类型
     * @return {@link BeanDefinition }
     * @author liuzhiyong
     * @date 2023/10/20
     */
    @Nullable
    @Override
    public BeanDefinition findBeanDefinition(String name, Class<?> requiredType) {
        BeanDefinition def = findBeanDefinition(name);
        if (def == null) {
            return null;
        }
        if (!requiredType.isAssignableFrom(def.getBeanClass())) {
            throw new BeanNotOfRequiredTypeException(String.format("Autowire required type '%s' but bean '%s' has actual type '%s'.", requiredType.getName(),
                    name, def.getBeanClass().getName()));
        }
        return def;
    }

    /**
     * 根据Type查找若干个BeanDefinition，返回0个或多个。
     *
     * @param type
     * @return {@link List<BeanDefinition> }
     * @author liuzhiyong
     * @date 2023/10/20
     */
    @Override
    public List<BeanDefinition> findBeanDefinitions(Class<?> type) {
        return this.beans.values().stream()
                // 过滤指定类型的Bean Definition
                // type.isAssignableFrom() 过滤出type的子类的BeanDefinition
                .filter(def -> type.isAssignableFrom(def.getBeanClass()))
                // 排序
                .sorted()
                .collect(Collectors.toList());
    }

    /**
     * 根据Type查找某个BeanDefinition，如果不存在返回null，
     * 如果存在多个返回@Primary标注的一个，
     * 如果有多个@Primary标注，或没有@Primary标注但找到多个，均抛出NoUniqueBeanDefinitionException
     *
     * @param type
     * @return {@link BeanDefinition }
     * @author liuzhiyong
     * @date 2023/10/20
     */
    @Nullable
    @Override
    public BeanDefinition findBeanDefinition(Class<?> type) {
        List<BeanDefinition> defs = findBeanDefinitions(type);
        if (defs.isEmpty()) {
            return null;
        }
        if (defs.size() == 1) {
            return defs.get(0);
        }
        // 超过一个Bean, 返回加了@Primary注解的BeanDefinition
        List<BeanDefinition> primaryDefs = defs.stream().filter(def -> def.isPrimary()).collect(Collectors.toList());
        if (primaryDefs.size() == 1) {
            return primaryDefs.get(0);
        }
        if (primaryDefs.isEmpty()) {
            throw new NoUniqueBeanDefinitionException(String.format("Multiple bean with type '%s' found, but no @Primary specified.", type.getName()));
        } else {
            throw new NoUniqueBeanDefinitionException(String.format("Multiple bean with type '%s' found, and multiple @Primary specified.", type.getName()));
        }
    }


    /**
     * 创建一个Bean，但不进行字段和方法级别的注入。
     * 如果创建的Bean不是Configuration，则在构造方法/工厂方法中注入的依赖Bean会自动创建
     *
     * @param def bean的定义信息
     * @return {@link Object }  bean对象
     * @author liuzhiyong
     * @date 2023/10/20
     */
    @Override
    public Object createBeanAsEarlySingleton(BeanDefinition def) {
        logger.atDebug().log("Try create bean '{}' as early singleton: {}", def.getName(), def.getBeanClass().getName());
        // 将正在创建的beanName添加到set集合, 会判断集合中是否包含
        if (!this.creatingBeanNames.add(def.getName())) {
            // 检测到重复创建Bean导致的循环依赖:
            throw new UnsatisfiedDependencyException(String.format("Circular dependency detected when create bean '%s'", def.getName()));
        }
        // 创建方式: 构造方法或者工厂方法
        // 创建Bean的方式有两种, 一种是使用构造方法,例如@Component注解标注的类, 另一种是使用工厂方法,被@Bean注解标注的方法
        // 被@Component标注的类,创建的BeanDefinition是没有factoryName和factoryMethod的
        Executable createFn = null;
        if (def.getFactoryName() == null) {
            // 没有factoryName, 使用构造方法创建Bean
            createFn = def.getConstructor();
        } else {
            // 通过工厂方法创建Bean
            createFn = def.getFactoryMethod();
        }

        // 创建参数
        // 获取参数数组
        Parameter[] parameters = createFn.getParameters();
        // 获取参数注解数组
        Annotation[][] parameterAnnos = createFn.getParameterAnnotations();
        Object[] args = new Object[parameters.length];

        for (int i = 0; i < parameters.length; i++) {
            final Parameter param = parameters[i];
            final Annotation[] paramAnnos = parameterAnnos[i];
            Value value = ClassUtils.getAnnotation(paramAnnos, Value.class);
            Autowired autowired = ClassUtils.getAnnotation(paramAnnos, Autowired.class);

            // @Configuration类型Bean是工厂, 不允许使用@Autowired创建
            final boolean isConfiguration = isConfigurationDefinition(def);
            if (isConfiguration && autowired != null) {
                throw new BeanCreationException(
                        String.format("Cannot specify @Autowired when create @Configuration bean '%s': %s.", def.getName(), def.getBeanClass().getName()));
            }

            // 参数需要@Value或@Autowired两者之一
            // 参数上@Value和@Autowired都有, 抛出异常
            if (value != null &&  autowired != null) {
                throw new BeanCreationException(
                        String.format("Cannot specify both @Autowired and @Value when create bean '%s': %s.", def.getName(), def.getBeanClass().getName()));
            }
            // 参数上@Value和@Autowired都没有, 抛出异常
//            if (value == null && autowired == null) {
//                throw new BeanCreationException(
//                        String.format("Must specify @Autowired or @Value when create bean '%s': %s.", def.getName(), def.getBeanClass().getName()));
//            }
            // 参数类型:
            final Class<?> type = param.getType();
            if (value != null) {
                // 参数是@Value
                args[i] = this.propertyResolver.getRequiredProperty(value.value(), type);
            } else {
                BeanDefinition dependsOnDef = null;
                if (autowired != null) {
                    // 参数是@Autowired
                    String name = autowired.name();
                    boolean required = autowired.value();
                    // 依赖的BeanDefinition
                    // 如果是按名称注入, 注入的Bean类型与参数类型不一致会抛出异常
                    dependsOnDef = name.isEmpty() ? findBeanDefinition(type) : findBeanDefinition(name, type);
                    if (required && dependsOnDef == null) {
                        // 必须的参数, 但是没有获取到BeanDefinition
                        throw new BeanCreationException(String.format("Missing autowired bean with type '%s' when create bean '%s': %s.", type.getName(),
                                def.getName(), def.getBeanClass().getName()));
                    }
                } else {
                    dependsOnDef = findBeanDefinition(type);
                    if (dependsOnDef == null) {
                        // 必须的参数, 但是没有获取到BeanDefinition
                        throw new BeanCreationException(String.format("Missing bean with type '%s' when create bean '%s': %s.", type.getName(),
                                def.getName(), def.getBeanClass().getName()));
                    }
                }
                if (dependsOnDef != null) {
                    // 获取依赖的Bean
                    Object autowiredBeanInstance = dependsOnDef.getInstance();
                    if (autowiredBeanInstance == null && !isConfiguration) {
                        // 当前依赖的Bean尚未实例化, 递归调用实例化依赖Bean
                        autowiredBeanInstance = createBeanAsEarlySingleton(dependsOnDef);
                    }
                    args[i] = autowiredBeanInstance;
                } else {
                    args[i] = null;
                }
            }

        }

        // 创建Bean实例
        Object instance = null;
        if (def.getFactoryName() == null) {
            // 使用构造方法创建对象
            try {
                instance = def.getConstructor().newInstance(args);
            } catch (Exception e) {
                throw new BeanCreationException(String.format("Exception when create bean '%s': %s", def.getName(), def.getBeanClass().getName()), e);
            }
        } else {
            // 使用工厂方法创建对象, 也就是添加了@Bean注解的方法

            // 获取工厂的Bean, 也就是加了@Configuration注解的Bean
            Object configInstance = getBean(def.getFactoryName());
            // 执行工厂方法, 也就是使用反射执行加了@Configuration注解的类里面标注了@Bean方法
            try {
                instance = def.getFactoryMethod().invoke(configInstance, args);
            } catch (Exception e) {
                throw new BeanCreationException(String.format("Exception when create bean '%s': %s", def.getName(), def.getBeanClass().getName()), e);
            }
        }
        // 设置实例到BeanDefinition
        def.setInstance(instance);

        // 调用BeanPostProcessor处理Bean
        // 因为使用的是beanPostProcessors集合, 在创建Configuration的Bean和BeanPostProcessor的Bean的时候, 集合还没有元素,
        // 所以只有创建普通的Bean的时候, 才会使用BeanPostProcessor处理Bean
        for (BeanPostProcessor processor : beanPostProcessors) {
            // 处理之后的bean
            // 默认的BeanPostProcessor接口是返回原有的Bean的,不做处理
            // 子类实现接口, 重写postProcessBeforeInitialization函数的话, 需要通过instanceof关键字自行判断bean的类型, 只处理指定类型, 不符合条件的, 还是会返回原来的Bean
            Object processed = processor.postProcessBeforeInitialization(def.getInstance(), def.getName());
            // processed不能为null, 不能把原来的Bean处理成一个null
            if (processed == null) {
                throw new BeanCreationException(String.format("PostBeanProcessor returns null when process bean '%s' by %s", def.getName(), processor));
            }
            // 如果BeanPostProcessor替换了原始的Bean,则更新Bean的引用:
            if (def.getInstance() != processed) {
                logger.atDebug().log("Bean '{}' was replaced by post processor {}.", def.getName(), processor.getClass().getName());
                def.setInstance(processed);
            }
        }
        return def.getInstance();
    }

    /**
     * 通过属性和setter方法注入依赖
     * 处理@Autowired 和 @Value 注解标注的属性和方法
     *
     * @param def BeanDefinition bean的定义信息
     * @author liuzhiyong
     * @date 2023/10/23
     */
    void injectBean(BeanDefinition def) {
        // 获取当前Bean实例, 或者被代理的原有Bean实例
        final Object beanInstance = getProxiedInstance(def);
        try {
            injectProperties(def, def.getBeanClass(), beanInstance);
        } catch (ReflectiveOperationException e) {
            throw new BeanCreationException(e);
        }
    }

    /**
     * 调用init方法
     * 加了@PostConstruct注解的方法
     * 或者@Bean注解指定了初始化函数名的方法
     *
     * @param def bean的定义信息
     * @author liuzhiyong
     * @date 2023/10/23
     */
    void initBean(BeanDefinition def) {
        // 获取当前Bean实例, 或者被代理的原有Bean实例
        final Object beanInstance = getProxiedInstance(def);
        // 调用init方法或者@Bean注解指定了初始化函数名的方法
        callMethod(beanInstance, def.getInitMethod(), def.getInitMethodName());

        // 调用BeanPostProcessor.postProcessAfterInitialization():
        // TODO 这里为什么操作的是def.getInstance() 而不是使用 上面的beanInstance, 因为def.getInstance()有可能是代理类
        beanPostProcessors.forEach(beanPostProcessor -> {
            Object processedInstance = beanPostProcessor.postProcessAfterInitialization(def.getInstance(), def.getName());
            if (processedInstance != def.getInstance()) {
                logger.atDebug().log("BeanPostProcessor {} return different bean from {} to {}.", beanPostProcessor.getClass().getSimpleName(),
                        def.getInstance().getClass().getName(), processedInstance.getClass().getName());
                def.setInstance(processedInstance);
            }
        });
    }

    /**
     * 获取Bean实例
     * 因为BeanPostProcessor可以生成代理类, 替换掉原来的Bean, 这里需要判断一下, 如果当前Bean是代理类的话要返回原来的Bean
     *
     * @param def bean的定义信息
     * @return {@link Object } bean
     * @author liuzhiyong
     * @date 2023/10/24
     */
    private Object getProxiedInstance(BeanDefinition def) {
        Object beanInstance = def.getInstance();
        // 如果Proxy改变了原始Bean，又希望注入到原始Bean，则由BeanPostProcessor指定原始Bean:
        // 因为执行BeanPostProcessor的时候, 是排过序的, 多个BeanPostProcessor可以操作同一个类, 所以需要逆向执行, 获取原来的Bean
        List<BeanPostProcessor> reversedBeanPostProcessors = new ArrayList<>(this.beanPostProcessors);
        Collections.reverse(reversedBeanPostProcessors);
        for (BeanPostProcessor beanPostProcessor : reversedBeanPostProcessors) {
            // 这个方法不会返回null, 如果BeanPostProcessor没有获取到原有的Bean的话, 说明当前BeanPostProcessor并没有修改当前的Bean, 这个函数也会入参的Bean, 返回值和当前的Bean相等, 进不做处理入下一次循环
            Object restoredInstance = beanPostProcessor.postProcessOnSetProperty(beanInstance, def.getName());
            // 如果当前的Bean和之前的Bean不一样, 说明Bean被替换过, 还原回去 .
            if (restoredInstance != beanInstance) {
                logger.atDebug().log("BeanPostProcessor {} specified injection from {} to {}.", beanPostProcessor.getClass().getSimpleName(),
                        beanInstance.getClass().getSimpleName(), restoredInstance.getClass().getSimpleName());
                beanInstance = restoredInstance;
            }
        }
        return beanInstance;
    }


    /**
     * 注入属性
     *
     * @param def bean的定义信息
     * @param clazz 当前class
     * @param bean 当前的bean
     * @author liuzhiyong
     * @date 2023/10/23
     */
    void injectProperties(BeanDefinition def, Class<?> clazz, Object bean) throws ReflectiveOperationException {
        // 在当前类查找Field和Method并注入
        // getDeclaredFields()函数会返当前类声明的所有属性, 不会返回父类的属性
        for (Field f : clazz.getDeclaredFields()) {
            tryInjectProperties(def, clazz, bean, f);
        }
        for (Method m : clazz.getDeclaredMethods()) {
            tryInjectProperties(def, clazz, bean, m);
        }

        // 在父类查找Field和Method并注入
        Class<?> superClazz = clazz.getSuperclass();
        if (superClazz != null) {
            injectProperties(def, superClazz, bean);
        }
    }

    /**
     * 注入单个属性
     *
     * @param def bean的定义信息
     * @param clazz class
     * @param bean bean
     * @param acc 反射类的基类
     * @author liuzhiyong
     * @date 2023/10/23
     */
    void tryInjectProperties(BeanDefinition def, Class<?> clazz, Object bean, AccessibleObject acc) throws ReflectiveOperationException {
        Value value = acc.getAnnotation(Value.class);
        Autowired autowired = acc.getAnnotation(Autowired.class);
        // 属性或者方法上没有添加 @Value 和 @Autowired 中任何一个注解
        if (value == null && autowired == null) {
            return;
        }

        Field field = null;
        Method method = null;

        if (acc instanceof Field f) {
            // 校验权限
            checkFieldOrMethod(f);
            f.setAccessible(true);
            field = f;
        }
        if (acc instanceof Method m) {
            // 校验权限
            checkFieldOrMethod(m);
            // 校验参数
            if (m.getParameters().length != 1) {
                throw new BeanDefinitionException(
                        String.format("Cannot inject a non-setter method %s for bean '%s': %s", m.getName(), def.getName(), def.getBeanClass().getName()));
            }
            m.setAccessible(true);
            method = m;
        }
        String accessibleName =field != null ? field.getName() : method.getName();
        Class<?> accessibleType = field != null ? field.getType() :method.getParameterTypes()[0];
        // 不能@Value 和 @Autowired两个注解都有
        if (value != null && autowired != null) {
            throw new BeanCreationException(String.format("Cannot specify both @Autowired and @Value when inject %s.%s for bean '%s': %s",
                    clazz.getSimpleName(), accessibleName, def.getName(), def.getBeanClass().getName()));
        }

        // @Value注入
        if (value != null) {
            Object propValue = this.propertyResolver.getRequiredProperty(value.value(), accessibleType);
            if (field != null) {
                logger.atDebug().log("Field injection: {}.{} = {}", def.getBeanClass().getName(), accessibleName, propValue);
                // 设置属性
                field.set(bean, propValue);
            }
            if (method != null) {
                logger.atDebug().log("Method injection: {}.{} ({})", def.getBeanClass().getName(), accessibleName, propValue);
                // 执行函数
                method.invoke(bean, propValue);
            }
        }

        // @Autowired注入
        if (autowired != null) {
            String name = autowired.name();
            boolean required = autowired.value();
            // @Autowired注解没有name ==> 根据类型注入, 根据属性或者方法入参的类型获取Bean
            // @Autowired注解指定name ==> 根据Bena的名称注入, 根据名称获取Bean, 并且校验类型
            // 结果目前可能为null
            Object depends = name.isEmpty() ? findBean(accessibleType) : findBean(name, accessibleType);
            // 如果required为true, 必须得值, depends不允许为null
            if (required && depends == null) {
                throw new UnsatisfiedDependencyException(String.format("Dependency bean not found when inject %s.%s for bean '%s': %s", clazz.getSimpleName(),
                        accessibleName, def.getName(), def.getBeanClass().getName()));
            }
            // depends 不为null, 设置值
            if (depends != null) {
                // @Autowired加在属性上, 设置属性
                if (field != null) {
                    logger.atDebug().log("Field injection: {}.{} = {}", def.getBeanClass().getName(), accessibleName, depends);
                    field.set(bean, depends);
                }
                // @Autowired加在方法上, 执行方法
                if (method != null) {
                    logger.atDebug().log("Mield injection: {}.{} ({})", def.getBeanClass().getName(), accessibleName, depends);
                    method.invoke(bean, depends);
                }
            }
        }
    }

    // findXxx与getXxx类似，但不存在时返回null

    @Nullable
    @SuppressWarnings("unchecked")
    protected <T> T findBean(String name, Class<T> requiredType) {
        BeanDefinition def = findBeanDefinition(name, requiredType);
        if (def == null) {
            return null;
        }
        return (T) def.getRequiredInstance();
    }

    /**
     * 根据类型获取Bean
     *
     * @param requiredType 类型
     * @return {@link T } Bean
     * @author liuzhiyong
     * @date 2023/10/23
     */
    @Nullable
    @SuppressWarnings("unchecked")
    protected <T> T findBean(Class<T> requiredType) {
        BeanDefinition def = findBeanDefinition(requiredType);
        if (def == null) {
            return null;
        }
        return (T) def.getRequiredInstance();
    }

    /**
     * 校验字段或者方法的权限
     *
     * @param m 字段或者方法
     * @author liuzhiyong
     * @date 2023/10/23
     */
    void checkFieldOrMethod(Member m) {
        int mod = m.getModifiers();
        // 弱依赖注入的属性或者方法不能被static修饰
        if (Modifier.isStatic(mod)) {
            throw new BeanDefinitionException("Cannot inject static field: " + m);
        }
        if (Modifier.isFinal(mod)) {
            // final 修饰的属性不能再次修改
            if (m instanceof Field field) {
                throw new BeanDefinitionException("Cannot inject final field: " + field);
            }
            if (m instanceof Method method) {
                logger.warn(
                        "Inject final method should be careful because it is not called on target bean when bean is proxied and may cause NullPointerException.");
            }
        }
    }

    /**
     * 反射执行init或者destroy方法
     *
     * @param beanInstance 当前实例
     * @param method init或者destroy 方法
     * @param namedMethod init或者destroy 方法名称
     * @author liuzhiyong
     * @date 2023/10/23
     */
    private void callMethod(Object beanInstance, Method method, String namedMethod) {
        // 有方法对象,使用初始化或者销毁注解, 可以获取到方法对象
        if (method != null) {
            try {
                method.invoke(beanInstance);
            } catch (ReflectiveOperationException e) {
                throw new BeanCreationException(e);
            }
        } else if (namedMethod != null) {
            // 使用@Bean注解指定, 需要根据函数名去执行函数
            // 查找initMethod/destroyMethod="xyz"，注意是在实际类型中查找:
            Method named = ClassUtils.getNamedMethod(beanInstance.getClass(), namedMethod);
            named.setAccessible(true);
            try {
                named.invoke(beanInstance);
            } catch (ReflectiveOperationException e) {
                throw new BeanCreationException(e);
            }
        }
    }


    @Override
    public boolean containsBean(String name) {
        return this.beans.containsKey(name);
    }

    /**
     * 通过name查找Bean, 如果不存在抛出NoSuchBeanDefinitionException
     *
     * @param name bean的名称
     * @return {@link T }   bean实例
     * @author liuzhiyong
     * @date 2023/10/21
     */
    @SuppressWarnings("unchecked")
    @Override
    public <T> T getBean(String name) {
        BeanDefinition def = this.beans.get(name);
        if (def == null) {
            throw new NoSuchBeanDefinitionException(String.format("No bean defined with name '%s'.", name));
        }
        return (T) def.getRequiredInstance();
    }

    @Override
    public <T> T getBean(String name, Class<T> requiredType) {
        T t = findBean(name, requiredType);
        if (t == null) {
            throw new NoSuchBeanDefinitionException(String.format("No bean defined with name '%s' and type '%s'.", name, requiredType));
        }
        return t;
    }

    /**
     * 通过Type查找Bean，不存在抛出NoSuchBeanDefinitionException，存在多个但缺少唯一@Primary标注抛出NoUniqueBeanDefinitionException
     */
    @SuppressWarnings("unchecked")
    @Override
    public <T> T getBean(Class<T> requiredType) {
        BeanDefinition def = findBeanDefinition(requiredType);
        if (def == null) {
            throw new NoSuchBeanDefinitionException(String.format("No bean defined with type '%s'.", requiredType));
        }
        return (T) def.getRequiredInstance();
    }

    @Override
    public <T> List<T> getBeans(Class<T> requiredType) {
        List<BeanDefinition> defs = findBeanDefinitions(requiredType);
        if (defs.isEmpty()) {
            return List.of();
        }
        List<T> list = new ArrayList<>(defs.size());
        for (var def : defs) {
            list.add((T) def.getRequiredInstance());
        }
        return list;
    }

    @Override
    public void close() {
        logger.info("Closing {}...", this.getClass().getName());
        this.beans.values().forEach(def -> {
            final Object beanInstance = getProxiedInstance(def);
            callMethod(beanInstance, def.getDestroyMethod(), def.getDestroyMethodName());
        });
        this.beans.clear();
        logger.info("{} closed.", this.getClass().getName());
        ApplicationContextUtils.setApplicationContext(null);
    }


}
